package com.small.xx.ai.file.service;

import com.small.xx.ai.file.config.FileProperties;
import com.small.xx.ai.file.dto.DirectoryBrowseRequest;
import com.small.xx.ai.file.dto.DirectoryBrowseResponse;
import com.small.xx.ai.file.dto.FileUploadRequest;
import com.small.xx.ai.file.dto.FileUploadResponse;
import com.small.xx.ai.file.entity.FileInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;

import jakarta.annotation.PreDestroy;
import java.io.*;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Stream;

/**
 * 文件目录服务类
 * 提供文件目录浏览相关功能
 * 
 * @author xx-ai
 * @version 1.0.0
 */
@Service
public class FileService {

    @Autowired
    private FileProperties fileProperties;
    
    private final ExecutorService executorService = Executors.newCachedThreadPool();

    /**
     * 浏览目录
     * 
     * @param request 目录浏览请求
     * @return 目录浏览响应
     */
    public DirectoryBrowseResponse browseDirectory(DirectoryBrowseRequest request) {
        DirectoryBrowseResponse response = new DirectoryBrowseResponse();
        
        try {
            String pathStr = request.getPath();
            if (pathStr == null || pathStr.trim().isEmpty()) {
                response.setAccessible(false);
                response.setErrorMessage("目录路径不能为空");
                return response;
            }

            Path path = Paths.get(pathStr);
            File directory = path.toFile();

            // 检查目录是否存在和可访问
            if (!directory.exists()) {
                response.setAccessible(false);
                response.setErrorMessage("目录不存在: " + pathStr);
                return response;
            }

            if (!directory.isDirectory()) {
                response.setAccessible(false);
                response.setErrorMessage("指定路径不是目录: " + pathStr);
                return response;
            }

            if (!directory.canRead()) {
                response.setAccessible(false);
                response.setErrorMessage("没有读取权限: " + pathStr);
                return response;
            }

            // 设置当前路径和父路径
            response.setCurrentPath(directory.getAbsolutePath());
            File parentFile = directory.getParentFile();
            if (parentFile != null) {
                response.setParentPath(parentFile.getAbsolutePath());
            }

            // 获取目录下的文件和子目录
            List<FileInfo> items = listDirectoryContents(directory, request.getShowHidden());
            
            // 添加性能信息到响应中
            int maxItems = fileProperties.getBrowser().getPerformance().getMaxItems();
            response.setItems(items);
            
            // 如果达到最大限制，在响应中添加提示
            if (items.size() >= maxItems) {
                response.setErrorMessage(String.format(
                    "目录包含大量文件，仅显示前 %d 个项目。如需查看更多，请进入子目录浏览。", 
                    maxItems
                ));
            }
            
            // 排序
            sortFileList(items, request.getSortBy(), request.getSortOrder());
            response.setAccessible(true);

            // 统计信息
            calculateStatistics(response, items);

        } catch (Exception e) {
            response.setAccessible(false);
            response.setErrorMessage("浏览目录时发生错误: " + e.getMessage());
        }

        return response;
    }

    /**
     * 获取目录内容列表
     * 
     * @param directory 目录文件对象
     * @param showHidden 是否显示隐藏文件
     * @return 文件信息列表
     */
    private List<FileInfo> listDirectoryContents(File directory, Boolean showHidden) {
        List<FileInfo> items = new ArrayList<>();
        
        // 获取性能配置
        int scanTimeout = fileProperties.getBrowser().getPerformance().getScanTimeout();
        int maxItems = fileProperties.getBrowser().getPerformance().getMaxItems();
        
        try {
            // 使用Future和超时机制扫描目录
            Future<List<FileInfo>> future = executorService.submit(() -> {
                return scanDirectoryWithLimit(directory, showHidden, maxItems);
            });
            
            try {
                // 等待扫描结果，设置超时时间
                items = future.get(scanTimeout, TimeUnit.MILLISECONDS);
                System.out.println(String.format(
                    "[DEBUG] 目录扫描完成 [%s]: 发现 %d 个项目", 
                    directory.getAbsolutePath(), items.size()
                ));
            } catch (TimeoutException e) {
                // 超时时取消任务
                future.cancel(true);
                System.err.println(String.format(
                    "[WARNING] 目录扫描超时 [%s]: 超过 %d 毫秒，返回部分结果", 
                    directory.getAbsolutePath(), scanTimeout
                ));
                
                // 尝试快速扫描前几个文件
                items = quickScanDirectory(directory, showHidden, Math.min(100, maxItems));
            } catch (ExecutionException e) {
                System.err.println("目录扫描执行错误: " + e.getCause().getMessage());
                e.getCause().printStackTrace();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.err.println("目录扫描被中断");
            }
            
        } catch (Exception e) {
            System.err.println("读取目录内容时发生错误: " + e.getMessage());
            e.printStackTrace();
        }

        return items;
    }
    
    /**
     * 带限制的目录扫描
     * 
     * @param directory 目录
     * @param showHidden 是否显示隐藏文件
     * @param maxItems 最大项目数
     * @return 文件信息列表
     */
    private List<FileInfo> scanDirectoryWithLimit(File directory, Boolean showHidden, int maxItems) {
        List<FileInfo> items = new ArrayList<>();
        
        try {
            // 多次尝试获取文件列表，确保一致性
            File[] files = null;
            int attempts = 0;
            final int maxAttempts = 3;
            
            while (files == null && attempts < maxAttempts) {
                try {
                    files = directory.listFiles();
                    attempts++;
                    
                    // 如果获取失败，短暂等待后重试
                    if (files == null && attempts < maxAttempts) {
                        Thread.sleep(50); // 等待50毫秒
                    }
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
            
            if (files != null) {
                // 检查是否被中断
                if (Thread.currentThread().isInterrupted()) {
                    return items;
                }
                
                // 先按文件名排序，确保每次遍历顺序一致
                java.util.Arrays.sort(files, (f1, f2) -> f1.getName().compareToIgnoreCase(f2.getName()));
                
                int processedCount = 0;
                for (File file : files) {
                    // 检查是否被中断或达到最大数量
                    if (Thread.currentThread().isInterrupted() || processedCount >= maxItems) {
                        System.out.println(String.format(
                            "[INFO] 达到最大扫描数量限制: %d/%d 项目已处理", 
                            processedCount, files.length
                        ));
                        break;
                    }
                    
                    try {
                        // 检查文件是否真实存在且可访问
                        if (!file.exists()) {
                            continue;
                        }
                        
                        // 如果不显示隐藏文件，跳过隐藏文件
                        if (!showHidden && file.isHidden()) {
                            continue;
                        }

                        FileInfo fileInfo = createFileInfo(file);
                        if (fileInfo != null) {
                            items.add(fileInfo);
                            processedCount++;
                        }
                    } catch (Exception e) {
                        // 记录具体文件的读取错误，但继续处理其他文件
                        System.err.println("读取文件信息时发生错误 [" + file.getName() + "]: " + e.getMessage());
                    }
                }
                
                if (files.length > maxItems) {
                    System.out.println(String.format(
                        "[INFO] 目录包含 %d 个项目，仅显示前 %d 个", 
                        files.length, maxItems
                    ));
                }
            } else {
                System.err.println("无法获取目录文件列表，尝试了 " + maxAttempts + " 次");
            }
        } catch (Exception e) {
            // 记录日志或处理异常
            System.err.println("读取目录内容时发生错误: " + e.getMessage());
            e.printStackTrace();
        }

        return items;
    }
    
    /**
     * 快速扫描目录（用于超时情况）
     * 
     * @param directory 目录
     * @param showHidden 是否显示隐藏文件
     * @param maxItems 最大项目数
     * @return 文件信息列表
     */
    private List<FileInfo> quickScanDirectory(File directory, Boolean showHidden, int maxItems) {
        List<FileInfo> items = new ArrayList<>();
        
        try {
            File[] files = directory.listFiles();
            if (files != null && files.length > 0) {
                // 只处理前几个文件，快速返回
                int count = 0;
                for (File file : files) {
                    if (count >= maxItems) {
                        break;
                    }
                    
                    try {
                        if (!file.exists()) {
                            continue;
                        }
                        
                        if (!showHidden && file.isHidden()) {
                            continue;
                        }
                        
                        // 快速创建基本文件信息
                        FileInfo fileInfo = createBasicFileInfo(file);
                        if (fileInfo != null) {
                            items.add(fileInfo);
                            count++;
                        }
                    } catch (Exception e) {
                        // 忽略单个文件错误
                    }
                }
                
                System.out.println(String.format(
                    "[INFO] 快速扫描完成，返回 %d/%d 个项目", 
                    items.size(), files.length
                ));
            }
        } catch (Exception e) {
            System.err.println("快速扫描目录时发生错误: " + e.getMessage());
        }
        
        return items;
    }
    
    /**
     * 创建基本文件信息对象（用于快速扫描）
     * 
     * @param file 文件对象
     * @return 文件信息
     */
    private FileInfo createBasicFileInfo(File file) {
        try {
            FileInfo fileInfo = new FileInfo();
            
            fileInfo.setName(file.getName());
            fileInfo.setPath(file.getAbsolutePath());
            fileInfo.setIsDirectory(file.isDirectory());
            fileInfo.setSize(file.isDirectory() ? 0L : file.length());
            fileInfo.setReadable(file.canRead());
            fileInfo.setWritable(file.canWrite());
            
            // 简化的时间设置
            try {
                long lastModifiedTime = file.lastModified();
                if (lastModifiedTime > 0) {
                    LocalDateTime lastModified = LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(lastModifiedTime),
                        ZoneId.systemDefault()
                    );
                    fileInfo.setLastModified(lastModified);
                } else {
                    fileInfo.setLastModified(LocalDateTime.now());
                }
            } catch (Exception e) {
                fileInfo.setLastModified(LocalDateTime.now());
            }
            
            return fileInfo;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 创建文件信息对象
     * 
     * @param file 文件对象
     * @return 文件信息
     */
    private FileInfo createFileInfo(File file) {
        try {
            // 再次检查文件是否存在和可访问
            if (!file.exists()) {
                return null;
            }
            
            FileInfo fileInfo = new FileInfo();
            
            fileInfo.setName(file.getName());
            fileInfo.setPath(file.getAbsolutePath());
            
            // 安全地检查文件类型
            boolean isDirectory = false;
            try {
                isDirectory = file.isDirectory();
            } catch (SecurityException e) {
                System.err.println("无法检查文件类型 [" + file.getName() + "]: " + e.getMessage());
            }
            fileInfo.setIsDirectory(isDirectory);
            
            // 安全地获取文件大小
            long fileSize = 0L;
            if (!isDirectory) {
                try {
                    fileSize = file.length();
                } catch (SecurityException e) {
                    System.err.println("无法获取文件大小 [" + file.getName() + "]: " + e.getMessage());
                }
            }
            fileInfo.setSize(fileSize);
            
            // 安全地检查文件权限
            boolean readable = false;
            boolean writable = false;
            try {
                readable = file.canRead();
                writable = file.canWrite();
            } catch (SecurityException e) {
                System.err.println("无法检查文件权限 [" + file.getName() + "]: " + e.getMessage());
            }
            fileInfo.setReadable(readable);
            fileInfo.setWritable(writable);
            
            // 设置最后修改时间
            try {
                long lastModifiedTime = file.lastModified();
                if (lastModifiedTime > 0) {
                    LocalDateTime lastModified = LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(lastModifiedTime),
                        ZoneId.systemDefault()
                    );
                    fileInfo.setLastModified(lastModified);
                }
            } catch (Exception e) {
                System.err.println("无法获取文件修改时间 [" + file.getName() + "]: " + e.getMessage());
                // 使用当前时间作为默认值
                fileInfo.setLastModified(LocalDateTime.now());
            }

            // 设置文件扩展名
            if (!isDirectory) {
                String fileName = file.getName();
                int lastDotIndex = fileName.lastIndexOf('.');
                if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
                    fileInfo.setExtension(fileName.substring(lastDotIndex + 1).toLowerCase());
                }
            }

            // 设置父目录路径
            try {
                File parent = file.getParentFile();
                if (parent != null) {
                    fileInfo.setParentPath(parent.getAbsolutePath());
                }
            } catch (Exception e) {
                System.err.println("无法获取父目录路径 [" + file.getName() + "]: " + e.getMessage());
            }

            return fileInfo;
        } catch (Exception e) {
            System.err.println("创建文件信息对象时发生错误 [" + file.getName() + "]: " + e.getMessage());
            return null;
        }
    }

    /**
     * 对文件列表进行排序
     * 
     * @param items 文件列表
     * @param sortBy 排序字段
     * @param sortOrder 排序顺序
     */
    private void sortFileList(List<FileInfo> items, String sortBy, String sortOrder) {
        // 如果没有指定排序参数，则不进行排序
        if (sortBy == null || sortBy.trim().isEmpty()) {
            return;
        }

        Comparator<FileInfo> comparator = null;

        switch (sortBy.toLowerCase()) {
            case "name":
                comparator = Comparator.comparing(FileInfo::getName, String.CASE_INSENSITIVE_ORDER);
                break;
            case "size":
                comparator = Comparator.comparing(FileInfo::getSize, Comparator.nullsFirst(Long::compareTo));
                break;
            case "lastmodified":
                comparator = Comparator.comparing(FileInfo::getLastModified, Comparator.nullsFirst(LocalDateTime::compareTo));
                break;
            case "created":
                // 创建时间与修改时间相同，因为Java中无法直接获取创建时间
                comparator = Comparator.comparing(FileInfo::getLastModified, Comparator.nullsFirst(LocalDateTime::compareTo));
                break;
            default:
                // 默认按名称排序
                comparator = Comparator.comparing(FileInfo::getName, String.CASE_INSENSITIVE_ORDER);
        }

        // 目录优先排序
        Comparator<FileInfo> finalComparator = Comparator
            .comparing(FileInfo::getIsDirectory, Comparator.reverseOrder())
            .thenComparing(comparator);

        // 如果是降序，反转比较器
        if ("desc".equalsIgnoreCase(sortOrder)) {
            finalComparator = Comparator
                .comparing(FileInfo::getIsDirectory, Comparator.reverseOrder())
                .thenComparing(comparator.reversed());
        }

        items.sort(finalComparator);
    }

    /**
     * 计算统计信息
     * 
     * @param response 响应对象
     * @param items 文件列表
     */
    private void calculateStatistics(DirectoryBrowseResponse response, List<FileInfo> items) {
        int directoryCount = 0;
        int fileCount = 0;
        int imageCount = 0;
        long totalSize = 0;

        for (FileInfo item : items) {
            if (item.getIsDirectory()) {
                directoryCount++;
            } else {
                fileCount++;
                totalSize += item.getSize();
                
                // 统计图片文件数量
                if (isImageFile(item.getPath())) {
                    imageCount++;
                }
            }
        }

        response.setDirectoryCount(directoryCount);
        response.setFileCount(fileCount);
        response.setTotalSize(totalSize);
        
        // 输出调试信息（在开发阶段）
        String currentPath = response.getCurrentPath();
        if (currentPath != null) {
            System.out.println(String.format(
                "[DEBUG] 目录统计 [%s]: 总文件=%d, 图片文件=%d, 目录=%d",
                currentPath, fileCount, imageCount, directoryCount
            ));
        }
    }

    /**
     * 检查路径是否安全（防止路径遍历攻击）
     * 
     * @param path 路径
     * @return 是否安全
     */
    public boolean isPathSafe(String path) {
        if (path == null || path.trim().isEmpty()) {
            return false;
        }

        try {
            Path normalizedPath = Paths.get(path).normalize();
            String normalizedPathStr = normalizedPath.toString();
            
            // 检查是否包含危险字符
            if (normalizedPathStr.contains("..") || normalizedPathStr.contains("~")) {
                return false;
            }

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 格式化文件大小
     * 
     * @param bytes 字节数
     * @return 格式化后的大小字符串
     */
    public String formatFileSize(long bytes) {
        if (bytes < 1024) {
            return bytes + " B";
        } else if (bytes < 1024 * 1024) {
            return String.format("%.1f KB", bytes / 1024.0);
        } else if (bytes < 1024 * 1024 * 1024) {
            return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
        } else {
            return String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0));
        }
    }

    // ================ 文件上传下载功能 ================

    /**
     * 上传多个文件
     * 
     * @param files 上传的文件数组
     * @param request 上传请求参数
     * @return 上传响应列表
     */
    public List<FileUploadResponse> uploadFiles(MultipartFile[] files, FileUploadRequest request) {
        List<FileUploadResponse> responses = new ArrayList<>();
        
        if (files == null || files.length == 0) {
            responses.add(FileUploadResponse.error("没有文件需要上传", "NO_FILES"));
            return responses;
        }
        
        // 验证目标路径
        if (request.getTargetPath() == null || request.getTargetPath().trim().isEmpty()) {
            FileUploadResponse errorResponse = FileUploadResponse.error("目标路径不能为空", "EMPTY_PATH");
            for (int i = 0; i < files.length; i++) {
                responses.add(errorResponse);
            }
            return responses;
        }
        
        // 检查路径安全性
        if (!isPathSafe(request.getTargetPath())) {
            FileUploadResponse errorResponse = FileUploadResponse.error("不安全的路径", "UNSAFE_PATH");
            for (int i = 0; i < files.length; i++) {
                responses.add(errorResponse);
            }
            return responses;
        }
        
        // 创建目标目录（只需要创建一次）
        Path targetDir = Paths.get(request.getTargetPath());
        if (!Files.exists(targetDir)) {
            try {
                Files.createDirectories(targetDir);
            } catch (IOException e) {
                FileUploadResponse errorResponse = FileUploadResponse.error(
                    "无法创建目标目录: " + e.getMessage(), "CREATE_DIR_FAILED");
                for (int i = 0; i < files.length; i++) {
                    responses.add(errorResponse);
                }
                return responses;
            }
        }
        
        // 检查目标目录是否可写
        if (!Files.isWritable(targetDir)) {
            FileUploadResponse errorResponse = FileUploadResponse.error("目标目录不可写", "DIR_NOT_WRITABLE");
            for (int i = 0; i < files.length; i++) {
                responses.add(errorResponse);
            }
            return responses;
        }
        
        // 逐个处理文件上传
        for (MultipartFile file : files) {
            FileUploadResponse response = uploadSingleFile(file, request, targetDir);
            responses.add(response);
        }
        
        return responses;
    }
    
    /**
     * 上传单个文件的内部方法
     * 
     * @param file 上传的文件
     * @param request 上传请求参数
     * @param targetDir 目标目录
     * @return 上传响应
     */
    private FileUploadResponse uploadSingleFile(MultipartFile file, FileUploadRequest request, Path targetDir) {
        try {
            // 验证文件
            if (file == null || file.isEmpty()) {
                return FileUploadResponse.error("文件不能为空", "EMPTY_FILE");
            }
            
            // 获取文件名
            String originalFileName = file.getOriginalFilename();
            if (originalFileName == null || originalFileName.trim().isEmpty()) {
                originalFileName = "unnamed_file";
            }
            
            // 清理文件名，移除不安全字符
            String safeFileName = sanitizeFileName(originalFileName);
            Path targetFile = targetDir.resolve(safeFileName);
            
            // 检查文件是否已存在
            if (Files.exists(targetFile) && !request.getOverwrite()) {
                return FileUploadResponse.error(
                    String.format("文件 '%s' 已存在，如需覆盖请勾选覆盖选项", safeFileName), 
                    "FILE_EXISTS");
            }
            
            // 检查文件大小限制（1024MB）
            long maxFileSize = 1024 * 1024 * 1024; // 1024MB
            if (file.getSize() > maxFileSize) {
                return FileUploadResponse.error(
                    String.format("文件 '%s' 大小超过限制（1024MB）", safeFileName), 
                    "FILE_TOO_LARGE");
            }
            
            // 保存文件
            try {
                file.transferTo(targetFile.toFile());
            } catch (IOException e) {
                return FileUploadResponse.error(
                    String.format("文件 '%s' 保存失败: %s", safeFileName, e.getMessage()), 
                    "SAVE_FAILED");
            }
            
            // 返回成功响应
            return FileUploadResponse.success(
                safeFileName,
                targetFile.toAbsolutePath().toString(),
                file.getSize(),
                file.getContentType()
            );
            
        } catch (Exception e) {
            String fileName = file.getOriginalFilename() != null ? file.getOriginalFilename() : "unknown";
            return FileUploadResponse.error(
                String.format("上传文件 '%s' 时发生错误: %s", fileName, e.getMessage()), 
                "UPLOAD_ERROR");
        }
    }

    /**
     * 上传文件
     * 
     * @param file 上传的文件
     * @param request 上传请求参数
     * @return 上传响应
     */
    public FileUploadResponse uploadFile(MultipartFile file, FileUploadRequest request) {
        try {
            // 验证文件
            if (file == null || file.isEmpty()) {
                return FileUploadResponse.error("文件不能为空", "EMPTY_FILE");
            }

            // 验证目标路径
            if (request.getTargetPath() == null || request.getTargetPath().trim().isEmpty()) {
                return FileUploadResponse.error("目标路径不能为空", "EMPTY_PATH");
            }

            // 检查路径安全性
            if (!isPathSafe(request.getTargetPath())) {
                return FileUploadResponse.error("不安全的路径", "UNSAFE_PATH");
            }

            // 创建目标目录
            Path targetDir = Paths.get(request.getTargetPath());
            if (!Files.exists(targetDir)) {
                try {
                    Files.createDirectories(targetDir);
                } catch (IOException e) {
                    return FileUploadResponse.error("无法创建目标目录: " + e.getMessage(), "CREATE_DIR_FAILED");
                }
            }

            // 检查目标目录是否可写
            if (!Files.isWritable(targetDir)) {
                return FileUploadResponse.error("目标目录不可写", "DIR_NOT_WRITABLE");
            }

            // 构建目标文件路径
            String originalFileName = file.getOriginalFilename();
            if (originalFileName == null || originalFileName.trim().isEmpty()) {
                originalFileName = "unnamed_file";
            }

            // 清理文件名，移除不安全字符
            String safeFileName = sanitizeFileName(originalFileName);
            Path targetFile = targetDir.resolve(safeFileName);

            // 检查文件是否已存在
            if (Files.exists(targetFile) && !request.getOverwrite()) {
                return FileUploadResponse.error("文件已存在，如需覆盖请勾选覆盖选项", "FILE_EXISTS");
            }

            // 检查文件大小限制（1024MB）
            long maxFileSize = 1024 * 1024 * 1024; // 1024MB
            if (file.getSize() > maxFileSize) {
                return FileUploadResponse.error("文件大小超过限制（1024MB）", "FILE_TOO_LARGE");
            }

            // 保存文件
            try {
                file.transferTo(targetFile.toFile());
            } catch (IOException e) {
                return FileUploadResponse.error("文件保存失败: " + e.getMessage(), "SAVE_FAILED");
            }

            // 返回成功响应
            return FileUploadResponse.success(
                safeFileName,
                targetFile.toAbsolutePath().toString(),
                file.getSize(),
                file.getContentType()
            );

        } catch (Exception e) {
            return FileUploadResponse.error("上传文件时发生错误: " + e.getMessage(), "UPLOAD_ERROR");
        }
    }

    /**
     * 下载文件
     * 
     * @param filePath 文件路径
     * @return 文件资源
     * @throws IOException 如果文件不存在或无法读取
     */
    public Resource downloadFile(String filePath) throws IOException {
        // 检查路径安全性
        if (!isPathSafe(filePath)) {
            throw new IOException("不安全的文件路径");
        }

        Path file = Paths.get(filePath);
        
        // 检查文件是否存在
        if (!Files.exists(file)) {
            throw new FileNotFoundException("文件不存在: " + filePath);
        }

        // 检查是否为文件（不是目录）
        if (Files.isDirectory(file)) {
            throw new IOException("指定路径是目录，不是文件: " + filePath);
        }

        // 检查文件是否可读
        if (!Files.isReadable(file)) {
            throw new IOException("文件不可读: " + filePath);
        }

        // 创建资源
        Resource resource = new UrlResource(file.toUri());
        if (!resource.exists() || !resource.isReadable()) {
            throw new IOException("无法读取文件: " + filePath);
        }

        return resource;
    }

    /**
     * 获取文件的MIME类型
     * 
     * @param filePath 文件路径
     * @return MIME类型
     */
    public String getContentType(String filePath) {
        try {
            Path file = Paths.get(filePath);
            String contentType = Files.probeContentType(file);
            return contentType != null ? contentType : "application/octet-stream";
        } catch (IOException e) {
            return "application/octet-stream";
        }
    }

    /**
     * 删除文件
     * 
     * @param filePath 文件路径
     * @return 是否删除成功
     */
    public boolean deleteFile(String filePath) {
        try {
            // 检查路径安全性
            if (!isPathSafe(filePath)) {
                return false;
            }

            Path file = Paths.get(filePath);
            
            // 检查文件是否存在
            if (!Files.exists(file)) {
                return false;
            }

            // 删除文件
            Files.delete(file);
            return true;
        } catch (IOException e) {
            System.err.println("删除文件失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 创建目录
     * 
     * @param dirPath 目录路径
     * @return 是否创建成功
     */
    public boolean createDirectory(String dirPath) {
        try {
            // 检查路径安全性
            if (!isPathSafe(dirPath)) {
                return false;
            }

            Path dir = Paths.get(dirPath);
            
            // 如果目录已存在，返回true
            if (Files.exists(dir)) {
                return Files.isDirectory(dir);
            }

            // 创建目录（包括父目录）
            Files.createDirectories(dir);
            return true;
        } catch (IOException e) {
            System.err.println("创建目录失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 清理文件名，移除不安全字符
     * 
     * @param fileName 原始文件名
     * @return 清理后的文件名
     */
    private String sanitizeFileName(String fileName) {
        if (fileName == null) {
            return "unnamed_file";
        }

        // 移除路径分隔符和其他不安全字符
        String cleaned = fileName.replaceAll("[/\\\\:*?\"<>|]", "_");
        
        // 移除前后空格
        cleaned = cleaned.trim();
        
        // 如果文件名为空或只包含点，使用默认名称
        if (cleaned.isEmpty() || cleaned.matches("^\\.+$")) {
            cleaned = "unnamed_file";
        }

        // 限制文件名长度
        if (cleaned.length() > 255) {
            String extension = "";
            int lastDotIndex = cleaned.lastIndexOf('.');
            if (lastDotIndex > 0) {
                extension = cleaned.substring(lastDotIndex);
                cleaned = cleaned.substring(0, lastDotIndex);
            }
            cleaned = cleaned.substring(0, Math.min(cleaned.length(), 255 - extension.length())) + extension;
        }

        return cleaned;
    }

    /**
     * 检查文件是否为图片
     * 
     * @param filePath 文件路径
     * @return 是否为图片
     */
    public boolean isImageFile(String filePath) {
        if (filePath == null || filePath.trim().isEmpty()) {
            return false;
        }
        
        try {
            // 检查文件是否存在
            File file = new File(filePath);
            if (!file.exists() || file.isDirectory()) {
                return false;
            }
            
            String extension = getFileExtension(filePath).toLowerCase();
            boolean isImageByExtension = extension.matches("jpg|jpeg|png|gif|bmp|svg|webp");
            
            // 如果扩展名匹配，进一步验证文件是否真的可读
            if (isImageByExtension) {
                try {
                    // 检查文件是否可读且大小大于0
                    return file.canRead() && file.length() > 0;
                } catch (SecurityException e) {
                    // 如果无法检查权限，仅基于扩展名判断
                    return true;
                }
            }
            
            return false;
        } catch (Exception e) {
            System.err.println("检查图片文件时发生错误 [" + filePath + "]: " + e.getMessage());
            return false;
        }
    }

    /**
     * 获取图片信息
     * 
     * @param filePath 图片文件路径
     * @return 图片信息映射
     */
    public java.util.Map<String, Object> getImageInfo(String filePath) {
        java.util.Map<String, Object> imageInfo = new java.util.HashMap<>();
        
        try {
            java.io.File file = new java.io.File(filePath);
            if (!file.exists() || !file.isFile()) {
                return imageInfo;
            }
            
            // 基本信息
            imageInfo.put("name", file.getName());
            imageInfo.put("size", file.length());
            imageInfo.put("lastModified", file.lastModified());
            imageInfo.put("extension", getFileExtension(filePath));
            
            // 尝试读取图片尺寸（简单实现）
            try {
                java.awt.image.BufferedImage bufferedImage = javax.imageio.ImageIO.read(file);
                if (bufferedImage != null) {
                    imageInfo.put("width", bufferedImage.getWidth());
                    imageInfo.put("height", bufferedImage.getHeight());
                    imageInfo.put("colorModel", bufferedImage.getColorModel().getClass().getSimpleName());
                }
            } catch (Exception e) {
                // 如果无法读取图片尺寸，忽略错误
                System.err.println("无法读取图片尺寸: " + e.getMessage());
            }
            
        } catch (Exception e) {
            System.err.println("获取图片信息时发生错误: " + e.getMessage());
        }
        
        return imageInfo;
    }

    /**
     * 生成图片缩略图（简单实现）
     * 
     * @param originalPath 原始图片路径
     * @param maxWidth 最大宽度
     * @param maxHeight 最大高度
     * @return 缩略图资源
     * @throws IOException 如果处理失败
     */
    public Resource generateThumbnail(String originalPath, int maxWidth, int maxHeight) throws IOException {
        // 检查路径安全性
        if (!isPathSafe(originalPath)) {
            throw new IOException("不安全的文件路径");
        }

        java.io.File originalFile = new java.io.File(originalPath);
        
        // 检查文件是否存在且为图片
        if (!originalFile.exists() || !isImageFile(originalPath)) {
            throw new FileNotFoundException("图片文件不存在或不是有效的图片格式");
        }

        try {
            // 读取原始图片
            java.awt.image.BufferedImage originalImage = javax.imageio.ImageIO.read(originalFile);
            if (originalImage == null) {
                throw new IOException("无法读取图片文件");
            }

            // 计算缩略尺寸
            int originalWidth = originalImage.getWidth();
            int originalHeight = originalImage.getHeight();
            
            // 如果图片尺寸小于最大尺寸，直接返回原图
            if (originalWidth <= maxWidth && originalHeight <= maxHeight) {
                return new UrlResource(originalFile.toURI());
            }
            
            // 计算缩放比例（保持宽高比）
            double widthRatio = (double) maxWidth / originalWidth;
            double heightRatio = (double) maxHeight / originalHeight;
            double ratio = Math.min(widthRatio, heightRatio);
            
            int newWidth = (int) (originalWidth * ratio);
            int newHeight = (int) (originalHeight * ratio);

            // 创建缩略图
            java.awt.image.BufferedImage thumbnailImage = new java.awt.image.BufferedImage(
                newWidth, newHeight, java.awt.image.BufferedImage.TYPE_INT_RGB);
                
            java.awt.Graphics2D g2d = thumbnailImage.createGraphics();
            g2d.setRenderingHint(java.awt.RenderingHints.KEY_INTERPOLATION, 
                               java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(java.awt.RenderingHints.KEY_RENDERING, 
                               java.awt.RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, 
                               java.awt.RenderingHints.VALUE_ANTIALIAS_ON);
            
            g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
            g2d.dispose();

            // 将缩略图转换为字节数组
            java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
            String formatName = getFileExtension(originalPath).toLowerCase();
            if (formatName.equals("jpg")) {
                formatName = "jpeg";
            }
            if (!javax.imageio.ImageIO.write(thumbnailImage, formatName, baos)) {
                // 如果不支持该格式，使用JPEG
                javax.imageio.ImageIO.write(thumbnailImage, "jpeg", baos);
            }
            
            byte[] thumbnailBytes = baos.toByteArray();
            
            // 返回资源
            return new org.springframework.core.io.ByteArrayResource(thumbnailBytes);
            
        } catch (IOException e) {
            throw new IOException("生成缩略图失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取图片的显示名称（包含尺寸信息）
     * 
     * @param filePath 图片文件路径
     * @return 显示名称
     */
    public String getImageDisplayName(String filePath) {
        java.io.File file = new java.io.File(filePath);
        String baseName = file.getName();
        
        try {
            java.util.Map<String, Object> imageInfo = getImageInfo(filePath);
            if (imageInfo.containsKey("width") && imageInfo.containsKey("height")) {
                return String.format("%s (%dx%d)", baseName, 
                    imageInfo.get("width"), imageInfo.get("height"));
            }
        } catch (Exception e) {
            // 如果获取尺寸失败，只返回文件名
        }
        
        return baseName;
    }

    /**
     * 检查文件是否为文本文件
     * 
     * @param filePath 文件路径
     * @return 是否为文本文件
     */
    public boolean isTextFile(String filePath) {
        if (filePath == null) {
            return false;
        }
        
        String extension = getFileExtension(filePath).toLowerCase();
        return extension.matches("txt|md|java|js|css|html|xml|json|yml|yaml|properties|log");
    }

    /**
     * 获取文件扩展名
     * 
     * @param filePath 文件路径
     * @return 文件扩展名（不包含点）
     */
    private String getFileExtension(String filePath) {
        if (filePath == null) {
            return "";
        }
        
        int lastDotIndex = filePath.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < filePath.length() - 1) {
            return filePath.substring(lastDotIndex + 1);
        }
        return "";
    }

    /**
     * 检查文件是否为视频文件
     * 
     * @param filePath 文件路径
     * @return 是否为视频文件
     */
    public boolean isVideoFile(String filePath) {
        if (filePath == null || filePath.trim().isEmpty()) {
            return false;
        }
        
        try {
            // 检查文件是否存在
            File file = new File(filePath);
            if (!file.exists() || file.isDirectory()) {
                return false;
            }
            
            String extension = getFileExtension(filePath).toLowerCase();
            boolean isVideoByExtension = extension.matches("mp4|avi|mkv|mov|wmv|flv|webm");
            
            // 如果扩展名匹配，进一步验证文件是否真的可读
            if (isVideoByExtension) {
                try {
                    // 检查文件是否可读且大小大于0
                    return file.canRead() && file.length() > 0;
                } catch (SecurityException e) {
                    // 如果无法检查权限，仅基于扩展名判断
                    return true;
                }
            }
            
            return false;
        } catch (Exception e) {
            System.err.println("检查视频文件时发生错误 [" + filePath + "]: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 重命名文件或目录
     * 
     * @param oldPath 原文件路径
     * @param newName 新文件名
     * @return 是否重命名成功
     */
    public boolean renameFile(String oldPath, String newName) {
        try {
            // 检查路径安全性
            if (!isPathSafe(oldPath)) {
                return false;
            }
            
            // 检查新文件名是否为空
            if (newName == null || newName.trim().isEmpty()) {
                return false;
            }
            
            // 清理文件名
            String safeNewName = sanitizeFileName(newName);
            
            // 获取原文件对象
            Path oldFile = Paths.get(oldPath);
            
            // 检查原文件是否存在
            if (!Files.exists(oldFile)) {
                return false;
            }
            
            // 构建新文件路径
            Path parentDir = oldFile.getParent();
            if (parentDir == null) {
                return false;
            }
            
            Path newFile = parentDir.resolve(safeNewName);
            
            // 检查新文件是否已存在
            if (Files.exists(newFile)) {
                return false;
            }
            
            // 重命名文件
            Files.move(oldFile, newFile);
            return true;
        } catch (IOException e) {
            System.err.println("重命名文件失败: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 应用关闭时清理资源
     */
    @PreDestroy
    public void cleanup() {
        if (executorService != null && !executorService.isShutdown()) {
            System.out.println("[INFO] 正在关闭文件服务线程池...");
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
                    System.out.println("[WARNING] 线程池未能在5秒内正常关闭，强制关闭");
                    executorService.shutdownNow();
                }
            } catch (InterruptedException e) {
                System.err.println("[ERROR] 线程池关闭过程中被中断");
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
}